package com.lxk.utils;

import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import com.google.common.collect.Lists;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @version 1.0
 * @Project: enterprise-credit
 * @Title:
 * @Description:
 * @Date: 2021/1/13 14:11
 * @Company: ByteDance
 * @Copyright: Copyright (c) 2021
 * @author: lixiaokun.roy@bytedance.com
 **/
public class SensitiveLogConvert extends MessageConverter {

    private static String[] keywords = new String[]{"companyName","qualificationSerial","ledgerPersonName","ledgerPersonNo","bankCardNo","phoneNum","payNum","cooperateCardNo","applyInfo"};

    private static Map<String, List<String>> normalDependMap = new HashMap<>();

    private static Map<String, ACMachine> aCMachineMap = new HashMap<>();

    static {
        normalDependMap.put("value", Lists.newArrayList("traceId"));
        normalDependMap.entrySet().forEach(item -> {
            List<String> value = item.getValue();
            String[] dependWords = value.toArray(new String[value.size()]);
            ACMachine depandMachine = new ACMachine(dependWords);
            aCMachineMap.put(item.getKey(), depandMachine);
        });
    }

    private static ACMachine acMachine = new ACMachine(keywords);


    public static void main(String[] args) {
        String value = "LogHelper.java:26 172.17.0.1 ad.billing.enterprise_credit_http_service 20210113173933010227024166438A229 default unknown [qtp1087332948-25] method:queryApplyInfo params:{\"request\":{\"appId\":\"ocean_engine_app\",\"data\":{\"accountId\":1686602647603214,\"companyId\":1019512309},\"nonce\":67534,\"signature\":\"tiuZ1BIqOWdcSxOajALhfDpM1mY=\",\"timestamp\":1610530773}} result:{\"code\":0,\"data\":{\"companyId\":1019512309,\"companyName\":\"陈孙坊的公司\",\"creditRateType\":3,\"ledgerPersonName\":\"陈孙坊\",\"ledgerPersonNo\":\"350426199703113519\",\"phoneNum\":\"18570003519\"},\"message\":\"SUCCESS\",\"status\":\"SUCCESS\"} time:964ms";
        System.out.println(doConvert(value));
    }


    @Override
    public String convert(ILoggingEvent event) {

        try {
            // 获取原始日志
            String requestLogMsg = event.getFormattedMessage();
            // 获取返回脱敏后的日志
            return doConvert(requestLogMsg);
        } catch (Exception e) {
            return event.getFormattedMessage();
        }
    }

    private static String doConvert(String msg) {
        List<ACMachine.StringSearchResult> findAll = acMachine.findAll(msg);
        if (CollectionUtils.isEmpty(findAll)) {
            return msg;
        }
        StringBuffer result = new StringBuffer();
        int copyStart = 0;


        for (int i = 0; i < findAll.size(); i++) {
            int currentIndex = findAll.get(i).getIndex();
            int nextIndex = msg.length();
            //本次处理这个key和下个key之间的部分
            if (i < findAll.size() - 1) {
                nextIndex = findAll.get(i + 1).getIndex();
            }

            if (copyStart == 0) {
                result.append(msg.substring( 0,currentIndex));
            }
            //如果配置的敏感词中有重复的key或者某个key是另一个key的前缀，则取下个一最长的前缀，忽略这一个
            if (currentIndex >= nextIndex) {
                continue;
            }
            result.append(handleOne(msg.substring(currentIndex, nextIndex), findAll.get(i).getKeyword(), msg));
            copyStart = nextIndex + 1;

        }
        return result.toString();
    }


    //再次用ac自动机判断依赖的key是否存在，存在时才需要脱敏，针对mtn配置的字段都放在value里
    private static boolean needHandle(String key, String all) {
        if (CollectionUtils.isEmpty(normalDependMap.get(key))) {
            return true;
        }
        //再次调用ac自动机判断msg中是否有依赖key
        List<ACMachine.StringSearchResult> findAll = aCMachineMap.get(key).findAll(all);
        return !CollectionUtils.isEmpty(findAll);
    }


    private static StringBuffer handleOne(String value, String key, String all) {

        //针对有依赖的敏感词key做处理
        if (!needHandle(key, all)) {
            return new StringBuffer(value);
        }

        int douEnd = value.indexOf(",", key.length());
        int kuoHaoEnd = value.indexOf("}", key.length());


        //选取一个可能的分隔符，同时避免加密太多
        int end = 0;
        if (douEnd < 0 && kuoHaoEnd < 0) {
            end = Math.min(value.length(), key.length() + 10);
        } else {
            end = Math.min(douEnd < 0 ? 9999 : douEnd, kuoHaoEnd < 0 ? 9999 : kuoHaoEnd);
        }

        if (end < key.length() + 1) {
            return new StringBuffer(value);
        }


        StringBuffer sb = new StringBuffer();
        sb.append(value.substring(0,key.length() + 1));
        for (int i = key.length() + 1; i < end; i++) {
            char v = value.charAt(i);

            //value是数组的特殊处理
            if (v == 91) {
                if (value.contains("]")) {
                    StringBuffer zhongkuohaoContent = new StringBuffer();
                    zhongkuohaoContent.append(value.substring( 0,i + 1));
                    zhongkuohaoContent.append("****");
                    zhongkuohaoContent.append(value.substring(value.indexOf("]"), value.length()));
                    return zhongkuohaoContent;
                } else {
                    sb.append("[");
                    continue;
                }
            }

            if (v > 128 || (v > 47 && v < 58) || (v > 64 && v < 123)) {
                //避免破坏json结构
                sb.append("*");
            } else {
                sb.append(value.charAt(i));
            }
        }
        sb.append(value.substring(end, value.length()));
        return sb;
    }


}